home *** CD-ROM | disk | FTP | other *** search
- //
- // MiscStringUNIX.m
- // Written by Don Yacktman Copyright (c) 1993 by Don Yacktman.
- // Version 1.95 All rights reserved.
- // This notice may not be removed from this source code.
- //
- // This object is included in the MiscKit by permission from the author
- // and its use is governed by the MiscKit license, found in the file
- // "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
- // for a list of all applicable permissions and restrictions.
- //
-
- #import <misckit/MiscString.h>
- #include <pwd.h>
-
- static char theMiscPathSeparator = '/';
- static char theMiscExtensionSeparator = '.';
-
- @implementation MiscString(Unix)
-
- // This category includes methods to support various UNIX features,
- // such as file/path name parsing and encryption of passwords.
-
- + setPathSeparator:(char)c { theMiscPathSeparator = c; return self; }
- + setExtensionSeparator:(char)c { theMiscExtensionSeparator = c; return self; }
- + (char)extensionSeparator { return theMiscExtensionSeparator; }
- + (char)pathSeparator { return theMiscPathSeparator; }
-
- - encrypt:salt
- { // encrypt as a UNIX password using the MiscString "salt" as the salt...
- // see crypt(3) for more info
- // The cast prevents a warning: -stringValue returns a const char *.
- // Assuming crypt() doesn't change the salt, the cast is OK.
- char *strv;
- if ([salt respondsTo:@selector(stringValue)])
- strv = (char *)[salt stringValue];
- else return nil;
- if (!(buffer && strv)) return nil;
- if (!length || !strlen(strv)) return nil;
- return [[[self class] alloc] initString:crypt(buffer, strv)];
- }
-
- - fileNameFromZone:(NXZone *)zone
- {
- return [self extractPart:MISC_STRING_LAST
- useAsDelimiter:theMiscPathSeparator
- caseSensitive:YES fromZone:zone];
- }
-
- - fileName
- {
- return [self fileNameFromZone:[self zone]];
- }
-
- - pathNameFromZone:(NXZone *)zone
- {
- id temp = [self left:[self rspotOf:theMiscPathSeparator] fromZone:zone];
- if (temp) return temp;
- return [[self class] new];
- }
-
- - pathName
- {
- return [self pathNameFromZone:[self zone]];
- }
-
- - fileExtensionFromZone:(NXZone *)zone
- {
- id temp = [self fileNameFromZone:[self zone]];
- id extension = [temp extractPart:MISC_STRING_LAST
- useAsDelimiter:theMiscExtensionSeparator
- caseSensitive:YES fromZone:zone];
- if ([temp isEqual:extension] ||
- (0 == [temp rspotOf:theMiscExtensionSeparator
- occurrenceNum:0 caseSensitive:YES]))
- [extension setStringValue:""];
- [temp free];
- return extension;
- }
-
- - fileExtension
- {
- return [self fileExtensionFromZone:[self zone]];
- }
-
- - fileBasenameFromZone:(NXZone *)zone
- {
- id base, temp = [self fileNameFromZone:[self zone]];
- int right = [temp rspotOf:theMiscExtensionSeparator
- occurrenceNum:0 caseSensitive:YES] - 1;
- if (right < 0) right = length - 1;
- base = [temp midFrom:0 to:right fromZone:zone];
- [temp free];
- return (base ? base : [[self class] new]);
- }
-
- - fileBasename
- {
- return [self fileBasenameFromZone:[self zone]];
- }
-
- - addExtensionIfNeeded:(const char *)aString
- {
- id ourExtension;
-
- if (!aString) return nil; // maybe we should _strip_ extensions here
-
- ourExtension = [self fileExtension];
-
- if ( [ourExtension length] == 0 ||
- [ourExtension cmp:aString] != 0 ) {
- if ([self charAt:(length - 1)] != theMiscExtensionSeparator)
- [self addChar:theMiscExtensionSeparator];
- [self cat:aString];
- }
- [ourExtension free];
- return self;
- }
-
- // June 1995: Carl Lindberg
- // Rewrote -replaceHomeWithTilde and -replaceTildeWithHome because they
- // a) had bad problems when user was root
- // b) thought all users home dirs were in the same directory, and
- // c) had problems when one username was a prefix of another
- // (e.g., "tom" and "tomsmith").
- // It was rather bad code, in retrospect. *Sigh* I hope I thought
- // of everything this time.
-
- - replaceHomeWithTilde
- {
- id homestr = [[self class] newWithString:NXHomeDirectory()];
- char rootdir[2] = {theMiscPathSeparator,0};
-
- // Make sure user isn't root, and also be careful not to
- // "/Users/tom" is not taken to be a match when the current
- // string is "/Users/tomsmith/Apps" (that's what the third
- // condition checks)
- if (![self compareTo:homestr n:[homestr length]] &&
- ([homestr cmp:rootdir]) &&
- (([self charAt:[homestr length]] == theMiscPathSeparator) ||
- ([homestr length] == [self length])))
- {
- [self replaceFrom:0 length:[homestr length] withChar:'~'];
- }
- else { // see if we can match a user's home dir, and if so
- // translate to "~username/subdir"
- struct passwd *userEntry;
-
- setpwent();
- while (userEntry = getpwent()) {
- [homestr setStringValue:userEntry->pw_dir];
- if (([homestr length]) &&
- ([homestr cmp:rootdir]) &&
- (![self compareTo:homestr n:[homestr length]]) &&
- (([self charAt:[homestr length]] == theMiscPathSeparator) ||
- ([homestr length] == [self length])))
- {
- [self replaceFrom:0 length:[homestr length] with:"~"];
- [self insert:userEntry->pw_name at:1];
- break;
- }
- }
- endpwent();
- }
- [homestr free];
- return self;
- }
-
- - replaceTildeWithHome
- {
- id home;
- char rootdir[2] = {theMiscPathSeparator,0};
-
- if (!buffer || (buffer[0] != '~')) return self;
-
- home = [[self class] newWithString:NXHomeDirectory()];
-
- if (length == 1) { //string is just "~"
- [self takeStringValueFrom:home];
- }
- else if (buffer[1] == theMiscPathSeparator) { //starts with "~/"
- if (![home cmp:rootdir]) // root--take out "~"
- [self removeFrom:0 to:0];
- else
- [self replaceFrom:0 length:1 withString:home];
- }
- else { // a "~username" variety; check if username exists
- int spot = [self spotOf:theMiscPathSeparator];
- id username;
- struct passwd *userEntry;
- if (spot == -1) spot = length;
-
- username = [self midFrom:1 to:spot-1];
- userEntry = getpwnam([username stringValue]);
- if (userEntry && userEntry->pw_dir) {
- [self replaceFrom:0 to:spot-1 with:userEntry->pw_dir];
- }
- [username free];
- }
- [home free];
- return self;
- }
-
- - (BOOL)isRelativePath
- // Returns YES if the path is non-empty and does NOT begin with pathSeparator.
- {
- id tempPath = [self pathName];
- if ([tempPath length] && ([tempPath charAt:0] != theMiscPathSeparator)) {
- [tempPath free];
- return YES;
- }
- [tempPath free];
- return NO;
- }
-
- - (BOOL)isAbsolutePath
- // Returns YES if the path is non-empty and DOES begin with pathSeparator.
- {
- id tempPath = [self pathName];
- if ([tempPath length] && ([tempPath charAt:0] == theMiscPathSeparator)) {
- [tempPath free];
- return YES;
- }
- [tempPath free];
- return NO;
- }
-
- - (BOOL)doesExistInFileSystem
- // Returns YES if the a file exists at our path, and is visible to the user
- // id of the process. A NO can mean any number of things, but a YES
- // definitely indicates that the file is there and visible.
- {
- struct stat statBuff;
- if (!buffer) return NO;
- if (stat([self stringValue], &statBuff) == -1) return NO;
- return YES;
- }
-
- - (BOOL)isFileOfType:(MiscFileType)fileType
- // Returns YES if the named file exists, and is visible to the user id of
- // the process and it is a file of type fileType. A NO can mean any number
- // of things, but a YES definitely indicates that the file is there and
- // visible and of the fileType type.
- {
- struct stat statBuff;
- if (!buffer) return NO;
- if (stat([self stringValue], &statBuff) == -1) return NO;
- return ((statBuff.st_mode & fileType) == fileType);
- }
-
- - pathComponentAt:(int)index
- {
- if ((index < 0) || (index >= [self numberOfPathComponents]))
- return [[self class] newWithString:""];
- return [self extractPart:([self isAbsolutePath] ? (index + 1) : index)
- useAsDelimiter:theMiscPathSeparator
- caseSensitive:YES fromZone:[self zone]];
- }
-
- - (int)numberOfPathComponents
- {
- return ([self numOfChar:theMiscPathSeparator] -
- ([self isAbsolutePath] ? 1 : 0));
- }
-
- /*
- * Modified [-setDirectory:file:] and [-initDirectory:file:] to use the
- * official misc path separator, rather than a hard-coded '/'. BJM 7/9/94
- */
- - setDirectory:(const char *)dir file:(const char *)file
- {
- return [self setFromFormat:"%s%c%s", dir, theMiscPathSeparator, file];
- }
-
- - initDirectory:(const char *)dir file:(const char *)file
- {
- return [self initFromFormat:"%s%c%s", dir, theMiscPathSeparator, file];
- }
-
- - (int)system
- {
- return system([self stringValue]);
- }
-
- - loadFromFile:(const char *)fileName
- {
- int theFile;
- struct stat fileInfo;
-
- if (!fileName || stat(fileName, &fileInfo) ||
- !(theFile = open(fileName, O_RDONLY))) {
- return nil;
- }
- if (fileInfo.st_size) {
- [self allocateBuffer:fileInfo.st_size]; // make sure we're big enough
- if (fileInfo.st_size != read(theFile, buffer, fileInfo.st_size)) {
- close(theFile);
- return nil;
- }
- }
- close(theFile);
- [self recalcLength];
- return self;
- }
-
- @end
-